package study.top.mydb;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;

import org.apache.log4j.Logger;

import study.top.common.DBHandler;
import study.top.common.DateTime;
import study.top.mydb.items.MemberItem;
import study.top.mydb.items.PaymentPItem;

/**
 * 회원 테이블
 * 
 * 회원가입(add), 로그인(login), 정보보기(show), 정보수정(edit),
 * 아이디찾기(searchID), 패스워드찾기(searchPW), 회원탈퇴(delete), 
 * 새로운패스워드생성(getNewPW), 아이디중복체크(idCheck), 모든회원보기(showAll), 
 * 모든회원보기에 페이지추가 (pagingShowAll)
 * 
 * @author 김미홍 
 */
public class Member {
	static Logger logger = Logger.getLogger(Member.class);	
	
	DBHandler db = null;
		
	public Member() {		
		db = DBHandler.getInstance();
	}
		
	private static final String TABLE = "member";
	
	/**
	 * 회원정보를 저장한다. 
	 * - 같은 아이디를 중복해서 갖을 경우 가입할수 없다.
	 * 
	 * @param id					아이디
	 * @param pw					비밀번호
	 * @param pw_as					비밀번호 질문대답
	 * @param name					이름
	 * @param jumin					주민번호
	 * @param email					이메일
	 * @param grade					회원등급
	 * @param zipcode				우편번호
	 * @param add1					주소
	 * @param add2					상세주소
	 * @param pw_question_seq		비밀번호 질문 일련번호
	 * @return int seq 				생성된 일련번호
	 */
	public int add(String id, String pw, String pw_as, String name, String jumin,
			String email, int grade, String zipcode, String add1, String add2,
			int pw_question_seq) {
		logger.debug("==========method start >> add");

		logger.debug("[PARAMS] id=" + id);
		logger.debug("[PARAMS] pw=" + pw);
		logger.debug("[PARAMS] pw_as=" + pw_as);
		logger.debug("[PARAMS] name=" + name);
		logger.debug("[PARAMS] jumin=" + jumin);
		logger.debug("[PARAMS] email=" + email);
		logger.debug("[PARAMS] grade=" + grade);
		logger.debug("[PARAMS] zipcode=" + zipcode);
		logger.debug("[PARAMS] add1=" + add1);
		logger.debug("[PARAMS] add2=" + add2);
		logger.debug("[PARAMS] pw_question_seq=" + pw_question_seq);
		
		int seq = -1;
		
		// SQL 인젝션 방어
		id = id.replace("'", "\'");
		pw = pw.replace("'", "\'");
		pw_as = pw_as.replace("'", "\'");
		name = name.replace("'", "\'");
		jumin = jumin.replace("'", "\'");
		email = email.replace("'", "\'");
		zipcode = zipcode.replace("'", "\'");
		add1 = add1.replace("'", "\'");
		add2 = add2.replace("'", "\'");
		
		boolean result = false;
		
		// idCheck(id) - 가입할수 있는 id라면 true를 리턴하는 메소드
		if (idCheck(id)) {
			// 트랜젝션
			db.beginTrans();
					
			// sql 
			String sql = "INSERT INTO member (id, pw, pw_question_seq, pw_as, name, jumin, email, grade, zipcode, add1, add2, reg_date, edit_date) " 
					+ "VALUE ('%s', password('%s'), %d, '%s', '%s', password('%s'), '%s', %d, '%s', '%s', '%s', '%s', '%s');";
						
			// reg_date, edit_date를 생성해서 리턴 
			String date = DateTime.getInstance().getNowDateTimeString();
			
			result = db.execSql(sql, id, pw, pw_question_seq, pw_as, name, jumin, email, grade, zipcode, add1, add2, date, date);
		} 
			
		if(result) {
			db.commit();
			seq = db.getMax(TABLE, "seq", null);
			
			WishList wish = new WishList();				
			wish.add(seq);
			
			logger.debug("처리결과 >> " + id + "회원의 회원가입 성공");
		} else {
			db.rollback();
			logger.error("처리결과 >> 회원가입 실패");
		}
				
		logger.debug("==========method end >> add");
		return seq;
	}

	/**
	 * 로그인을 한다.
	 * 
	 * @param id					아이디
	 * @param pw					비밀번호
	 * @return int seq				회원 일련번호
	 */
	public int login(String id, String pw) {
		logger.debug("==========method start >> login");

		logger.debug("[PARAMS] id=" + id);
		logger.debug("[PARAMS] pw=" + pw);
		
		int seq = -1;
		
		// sql 
		String sql = "SELECT seq FROM member WHERE id='%s' AND pw=password('%s')";
		
		ResultSet rs = db.getResult(sql, id, pw);
						
		// SQL이 성공이라면?
		if (rs != null) {
			try {
				// 데이터가 있다면?
				if (rs.next()) {
					seq = rs.getInt(1);
				}
						
				// ResultSet의 자원 반납(메모리 해제)
				rs.close();
				rs = null;
			} catch (SQLException e){
				e.printStackTrace();
			}
		}
		
		logger.debug("==========method end >> login");
		return seq;
	}

	/**
	 * 회원아이디를 이용해 선택한 회원의 모든정보를 보여준다.
	 * 
	 * @param seq				회원 일련번호
	 * @return MemberItem item 	회원의 모든정보
	 */
	public MemberItem show(int seq) {
		logger.debug("==========method start >> show");

		logger.debug("[PARAMS] seq=" + seq);
		
		MemberItem item = null;
								
		// sql - SELECT seq, id, pw, pw_as, name, jumin, email, grade, zipcode, add1, add2, pw_question_seq, reg_date, edit_date FROM member WHERE seq=1;
		String sql = "SELECT seq, id, pw, pw_as, name, jumin, email, grade, zipcode, add1, add2, pw_question_seq, reg_date, edit_date FROM member WHERE seq=%d";
								
		ResultSet rs = db.getResult(sql, seq);
		
		if(rs != null) {
			// 데이터 조회 결과 있는 경우
			try {
				rs.next();
				
				// 1) ResultSet의 모든 데이터를 변수로 추출
				int sno = rs.getInt(1);
				String id = rs.getString(2);
				String pw = rs.getString(3);
				String pw_as = rs.getString(4);
				String name = rs.getString(5);
				String jumin = rs.getString(6);
				String email = rs.getString(7);
				int grade = rs.getInt(8);
				String zipcode = rs.getString(9);
				String add1 = rs.getString(10);
				String add2 = rs.getString(11);
				int pw_question_seq = rs.getInt(12);
				String reg_date = rs.getString(13);
				String edit_date = rs.getString(14);
				
				// 2) 추출된 값을 객체로 구성
				item = new MemberItem(sno, id, pw, pw_as, name, jumin, email, grade, zipcode, add1, add2, pw_question_seq, reg_date, edit_date);
			
			} catch (SQLException e) {
				logger.error(e);
			} finally {
				// 3) 데이터 조회에 대한 메모리 반납
				try {
					rs.close();
				} catch (SQLException e) {}
				rs = null;
			}
		}
		
		if(item == null) {
			logger.error("회원 검색 실패");
		} else {
			logger.debug("회원 검색 성공");
			logger.debug(item.toString());
		}

		logger.debug("==========method end >> show");
		return item;
	}

	/**
	 * 회원정보를 수정한다. 
	 * pw, pw_question_seq, pw_as, email, grade, zipcode, add1, add2, edit_date 정보만 수정가능
	 * 
	 * @param seq				일련번호
	 * @param id				아이디
	 * @param pw				비밀번호
	 * @param pw_as				비밀번호 질문대답
	 * @param name				이름
	 * @param name				주민번호
	 * @param email				이메일
	 * @param grade				학년
	 * @param zipcode			우편번호
	 * @param add1				주소
	 * @param add2				상세주소
	 * @param pw_question_seq	비밀번호 질문 일련번호
	 * @return boolean result	회원의 수정여부
	 */	
	public boolean edit(int seq, String id, String pw, String pw_as, String name, String jumin, 
			String email, int grade, String zipcode, String add1, String add2,
			int pw_question_seq) {
		logger.debug("==========method start >> edit");
		
		logger.debug("[PARAMS] seq=" + seq);
		logger.debug("[PARAMS] id=" + id);
		logger.debug("[PARAMS] pw=" + pw);
		logger.debug("[PARAMS] pw_as=" + pw_as);
		logger.debug("[PARAMS] name=" + name);
		logger.debug("[PARAMS] email=" + email);
		logger.debug("[PARAMS] grade=" + grade);
		logger.debug("[PARAMS] zipcode=" + zipcode);
		logger.debug("[PARAMS] add1=" + add1);
		logger.debug("[PARAMS] add2=" + add2);
		logger.debug("[PARAMS] pw_question_seq=" + pw_question_seq);

		boolean result = false;
		
		// SQL 인젝션 방어
		id = id.replace("'", "\'");
		pw = pw.replace("'", "\'");
		pw_as = pw_as.replace("'", "\'");
		name = name.replace("'", "\'");
		jumin = jumin.replace("'", "\'");
		email = email.replace("'", "\'");
		zipcode = zipcode.replace("'", "\'");
		add1 = add1.replace("'", "\'");
		add2 = add2.replace("'", "\'");
						
		// 트랜젝션
		db.beginTrans();
						
		// sql 
		String sql = "UPDATE member SET pw=password('%s'), pw_question_seq=%d, pw_as='%s', email='%s', grade=%d, zipcode='%s', add1='%s', add2='%s', edit_date='%s' WHERE seq=%d"; 
		
		// reg_date, edit_date를 생성해서 리턴 
		String date = DateTime.getInstance().getNowDateTimeString();
				
		result = db.execSql(sql, pw, pw_question_seq, pw_as, email, grade, zipcode, add1, add2, date, seq);
				
		if(result) {
			db.commit();
			logger.debug("처리결과 >> " + id + "회원의 정보수정 성공");
		} else {
			db.rollback();
			logger.debug("==========method end >> edit");
		}
				
		logger.debug("==========method end >> edit");		
		return result;
	}	
	
	/**
	 * 회원의 아이디를 검색한다.
	 * 
	 * @param name				회원이름
	 * @param jumin				주민번호
	 * @param email				이메일
	 * @return	String			검색된 아이디
	 */
	public String searchID(String name, String jumin, String email) {
		logger.debug("==========method start >> searchID");

		logger.debug("[PARAMS] name=" + name);
		logger.debug("[PARAMS] jumin=" + jumin);
		logger.debug("[PARAMS] email=" + email);
		
		String id = null;
		
		// sql - SELECT id FROM member WHERE name='김미홍' AND email='vhongv@daum.net';
		String sql = "SELECT id FROM member WHERE name='%s' AND jumin=password('%s')";
										
		ResultSet rs = db.getResult(sql, name, jumin);
				
		if(rs != null) {
			// 데이터 조회 결과 있는 경우
			try {
				rs.next();

				id = rs.getString(1);
		
			} catch (SQLException e) {
				logger.error(e);
			} finally {
				// 3) 데이터 조회에 대한 메모리 반납
				try {
					rs.close();
				} catch (SQLException e) {}
				rs = null;
			}
		}
				
		if(id == null) {
			logger.error("아이디 찾기 실패");
		} else {
			logger.debug("아이디 찾기 성공");
		}
		
		logger.debug("==========method end >> searchID");
		return id;
	}
	
	/**
	 * 회원 비밀번호를 새로 작성해서 알려준다.
	 * 
	 * @param id		아이디
	 * @param name		회원이름
	 * @param email		이메일	
	 * @param pw_as		패스워드찾기 질문의 답
	 * @return new_pw	새로 만들어진 패스워드를 알려준다.
	 * @throws SQLException 
	 */
	public String searchPW(String id, String name, String jumin, String email) throws SQLException{
		logger.debug("==========method start >> searchPW");
		
		logger.debug("[PARAMS] id=" + id);
		logger.debug("[PARAMS] name=" + name);
		logger.debug("[PARAMS] pw_as=" + jumin);
		logger.debug("[PARAMS] email=" + email);

		String new_pw = null;
		String find_id = null;
		
		// sql
		String sql = "SELECT id FROM member WHERE (id='%s' AND name='%s' AND jumin=password('%s'))";
		String update_sql = "UPDATE member SET pw=password('%s'), edit_date='%s' WHERE id='%s'"; 
		
		ResultSet rs = db.getResult(sql, id, name, jumin);
		
		if(rs != null) {
			// 데이터 조회 결과 있는 경우
			try {
				rs.next();
				
				find_id = rs.getString(1);
				new_pw = getNewPW();		
			} catch (SQLException e) {
				logger.error(e);
			} finally {
				// 3) 데이터 조회에 대한 메모리 반납
				try {
					rs.close();
				} catch (SQLException e) {}
				rs = null;
			}
		}
		
		if(new_pw == null) {
			logger.error("패스워드 찾기 실패");
		} else {			
			logger.debug("패스워드 찾기 성공");
			
			boolean result = false;
			
			// reg_date, edit_date를 생성해서 리턴 
			String date = DateTime.getInstance().getNowDateTimeString();
			
			result = db.execSql(update_sql, new_pw, date, find_id);
			
			if(result) {
				logger.error("새 패스워드 저장 실패");
			} else {			
				logger.debug("새 패스워드 저장 성공");
			}
		}
		
		logger.debug("==========method end >> searchPW");
		return new_pw;
	}
	
	/**
	 * 회원 탈퇴를위해 아이디와 비밀번호를받는다.
	 * 
	 * @param seq 		회원 일련번호
	 * @param id 		아이디
	 * @param pw 		패스워드
	 * @return result 	회원탈퇴 여부
	 */
	public boolean delete(int seq, String id, String pw) {
		logger.debug("==========method start >> delete");	

		logger.debug("[PARAMS] seq=" + seq);
		logger.debug("[PARAMS] id=" + id);
		logger.debug("[PARAMS] pw=" + pw);
		
		boolean result = false, result2 = false, result3 = false, result4 = false, result5 = false;		
		
		// 트랜젝션
		db.beginTrans();
		
		String findseq = "SELECT seq FROM member WHERE id='%s' AND pw=password('%s')";
		
		ResultSet f_rs = db.getResult(findseq, id, pw);
		
		int f_seq = 0;
		
		if(f_rs != null) {
			// 데이터 조회 결과 있는 경우
			try {
				f_rs.next();

				f_seq = f_rs.getInt(1);
		
			} catch (SQLException e) {
				logger.error(e);
			} finally {
				// 3) 데이터 조회에 대한 메모리 반납
				try {
					f_rs.close();
				} catch (SQLException e) {}
				f_rs = null;
			}
		}
		
		if (seq == f_seq) {
			
			WishList wl = new WishList();
			result2 = wl.delete(seq);
			
			Board bo = new Board();
			result3 = bo.delete(seq);
			
			Review rv = new Review();
			result4 = rv.delete(seq);
			
			PaymentInfo pi = new PaymentInfo();
			result5 = pi.delete(seq);
						
			// sql
			// DELETE FROM member WHERE id='vhongv' AND pw=password('vhong')"
			String sql = "DELETE FROM member WHERE seq = %d";
			result = db.execSql(sql, seq);	
		}
				
		if(result && result2 && result3 && result4 && result5) {
			db.commit();
			logger.debug("처리결과 >> " + id + "회원의 탈퇴가 정상처리 되었습니다.");
			result = true;
		} else {
			db.rollback();
			logger.error("처리결과 >> 회원 탈퇴 실패 ");
			result = false;
		}
		
		logger.debug("==========method end >> delete");
		return result;
	}
	
	/** 새로운 7자리의 패스워드를 생성해서 리턴 */
	public String getNewPW() {
		logger.debug("==========method start >> getNewPW");
		
		String new_pw = "";
		
		for (int i = 0; i < 7; i++) {
			// 아스키번호 33번(!) 부터 126번(~)까지 문자중 7자 추출
            new_pw += ((char)((Math.random() * 58) + 65));
        }
		
		new_pw = new_pw.replace("'", "\'");
		
		logger.debug("==========method end >> getNewPW");
		return new_pw;
	}
	
	/** member DB를 검색해서 가입이 가능한 아이디이면 true를 리턴 */
	public boolean idCheck(String id) {
		logger.debug("==========method start >> idCheck");
		
		logger.debug("[PARAMS] id=" + id);
		
		boolean result = false;
		
		String where = "id='" + id +"'";
				
		int numId = db.getCount(TABLE, "id", where);
		
		if (numId == 0) {
			result = true;
		}
		
		logger.debug("==========method end >> idCheck");
		return result;
	}
		
	/** 동이름으로 검색해서 zipcode 와 주소1을 리턴 */
	public String getMemAddress(String dong) {
		logger.debug("==========method start >> getMemAddress");
		
		logger.debug("[PARAMS] dong=" + dong);
		
		String add1 = null;
		
		String sql = "SELECT zipcode, sido, sigungu, dong FROM tbl_zipcode WHERE dong='%s'";
				
		ResultSet rs = db.getResult(sql, dong);
		
		if(rs != null) {
			// 데이터 조회 결과 있는 경우
			try {
				rs.next();

				add1 = rs.getString(1) + " ";
				add1 += rs.getString(2) + " ";
				add1 += rs.getString(3) + " ";
				add1 += rs.getString(4);
		
			} catch (SQLException e) {
				logger.error(e);
			} finally {
				// 3) 데이터 조회에 대한 메모리 반납
				try {
					rs.close();
				} catch (SQLException e) {}
				rs = null;
			}
		}
		
		logger.debug("==========method end >> getMemAddress");
		return add1;
	}
	
	/**
	 * 회원아이디를 이용해 선택한 회원의 모든정보를 보여준다.
	 * 
	 * @return MemberItem item 	회원의 모든정보
	 */
	public ArrayList<MemberItem> showAll() {
		logger.debug("==========method start >> showAll");
		
		ArrayList<MemberItem> list = null;
								
		// sql - SELECT seq, id, pw, pw_as, name, jumin, email, grade, zipcode, add1, add2, pw_question_seq, reg_date, edit_date FROM member;
		String sql = "SELECT seq, id, pw, pw_as, name, jumin, email, grade, zipcode, add1, add2, pw_question_seq, reg_date, edit_date FROM member ORDER BY seq desc";
		
		ResultSet rs = db.getResult(sql);
		
		if(rs != null) {
			// 데이터 조회 결과 있는 경우
			try {
				list = new ArrayList<MemberItem>();
				
				while(rs.next()) {
							
					// 1) ResultSet의 모든 데이터를 변수로 추출
					int sno = rs.getInt(1);
					String id = rs.getString(2);
					String pw = rs.getString(3);
					String pw_as = rs.getString(4);
					String name = rs.getString(5);
					String jumin = rs.getString(6);
					String email = rs.getString(7);
					int grade = rs.getInt(8);
					String zipcode = rs.getString(9);
					String add1 = rs.getString(10);
					String add2 = rs.getString(11);
					int pw_question_seq = rs.getInt(12);
					String reg_date = rs.getString(13);
					String edit_date = rs.getString(14);
					
					// 2) 추출된 값을 객체로 구성
					MemberItem item = new MemberItem(sno, id, pw, pw_as, name, jumin, email, grade, zipcode, add1, add2, pw_question_seq, reg_date, edit_date);
				
					// 3) ArrayList에 추가
					list.add(item);
				}				
			} catch (SQLException e) {
				logger.error(e);
			} finally {
				// 3) 데이터 조회에 대한 메모리 반납
				try {
					rs.close();
				} catch (SQLException e) {}
				rs = null;
			}
		}
		
		if(list == null) {
			logger.error("전체 회원 검색 실패");
		} else {
			logger.debug("전체 회원 검색 성공");
		}

		logger.debug("==========method end >> showAll");
		return list;
	}
	
	/**
	 * 회원리스트에 페이징 적용
	 * 
	 * @param start		페이지의 시작 목록번호
	 * @param end		페이지의 끝 목록번호	 
	 * @return MemberItem item 	회원의 모든정보
	 */
	public ArrayList<MemberItem> pagingShowAll(int start, int end) {
		logger.debug("==========method start >> pagingShowAll");
		
		logger.debug("[PARAMS] start=" + start);
		logger.debug("[PARAMS] end=" + end);
		
		ArrayList<MemberItem> list = null;
								
		// sql - SELECT seq, id, pw, pw_as, name, jumin, email, grade, zipcode, add1, add2, pw_question_seq, reg_date, edit_date FROM member;
		String sql = "SELECT seq, id, pw, pw_as, name, jumin, email, grade, zipcode, add1, add2, pw_question_seq, reg_date, edit_date FROM member ORDER BY seq desc ";
		sql += "LIMIT %d, %d";
		
		ResultSet rs = db.getResult(sql, start, end);
		
		if(rs != null) {
			// 데이터 조회 결과 있는 경우
			try {
				list = new ArrayList<MemberItem>();
				
				while(rs.next()) {
							
					// 1) ResultSet의 모든 데이터를 변수로 추출
					int sno = rs.getInt(1);
					String id = rs.getString(2);
					String pw = rs.getString(3);
					String pw_as = rs.getString(4);
					String name = rs.getString(5);
					String jumin = rs.getString(6);
					String email = rs.getString(7);
					int grade = rs.getInt(8);
					String zipcode = rs.getString(9);
					String add1 = rs.getString(10);
					String add2 = rs.getString(11);
					int pw_question_seq = rs.getInt(12);
					String reg_date = rs.getString(13);
					String edit_date = rs.getString(14);
					
					// 2) 추출된 값을 객체로 구성
					MemberItem item = new MemberItem(sno, id, pw, pw_as, name, jumin, email, grade, zipcode, add1, add2, pw_question_seq, reg_date, edit_date);
				
					// 3) ArrayList에 추가
					list.add(item);
				}				
			} catch (SQLException e) {
				logger.error(e);
			} finally {
				// 3) 데이터 조회에 대한 메모리 반납
				try {
					rs.close();
				} catch (SQLException e) {}
				rs = null;
			}
		}
		
		if(list == null) {
			logger.error("전체 회원 검색 실패");
		} else {
			logger.debug("전체 회원 검색 성공");
		}

		logger.debug("==========method end >> pagingShowAll");
		return list;
	}
}